package com.acheli.rideable.factory.instance;

import com.acheli.registry.entity.model.OBJModelRegistry;
import com.acheli.registry.event.Debugging;
import com.acheli.registry.keybind.KeyBinding;
import com.acheli.registry.network.ACHMessages;
import com.acheli.registry.network.ACHeliPacketType;
import com.acheli.registry.network.packet.CustomSyncableC2SPacket;
import com.acheli.rideable.factory.ACHeliEntitiesFactory;
import com.acheli.rideable.functionLathes.ComponentFL;
import com.acheli.rideable.functionLathes.EntityFLProvider;
import com.acheli.rideable.entites.RideableEntity;
import com.acheli.rideable.functionLathes.RideableFL;
import com.acheli.rideable.functionLathes.component.SeatFL;
import com.acheli.rideable.functionLathes.component.GroundCheckFL;
import com.acheli.rideable.functionLathes.component.engine.EngineFL;
import com.acheli.rideable.functionLathes.component.engine.ModTestEngine;
import com.acheli.rideable.functionLathes.component.propeller.PropellerBase;
import com.acheli.rideable.functionLathes.component.stabilizer.StabilizerBase;
import com.acheli.utils.air.Aerodynamics;
import com.acheli.utils.math.angle.AbstractAngle;
import com.acheli.utils.math.angle.Angle;
import com.acheli.utils.physics.PhysicsEngine;
import com.acheli.utils.rotate.EntityDirectionUtils;
import com.acheli.utils.rotate.RotateWith;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.MoverType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import org.joml.Quaternionf;

public class UH_1D_SAR extends ACHeliEntitiesFactory<RideableEntity, RideableFL> {
    private static ItemStack bodyItemStack = new ItemStack(OBJModelRegistry.uh_1d_body.get());
//    private static ItemStack bodyItemStack2 = new ItemStack(ForgeRegistries.ITEMS.getValue(ResourceLocation.tryBuild(MODID, "uh_1d_body")));
    private static ItemStack mainPropellerItemStack = new ItemStack(OBJModelRegistry.uh_1d_main_propeller.get());
    private static ItemStack tinyPropellerItemStack = new ItemStack(OBJModelRegistry.uh_1d_tiny_propeller.get());
    public UH_1D_SAR(RideableEntity entity) {
        super(entity, new UH_1D_SAR_EntityFLProvider(new RideableFL()));

    }

    public static class UH_1D_SAR_EntityFLProvider extends EntityFLProvider<RideableEntity, RideableFL> {

        Vec3 lastPos;
        double speed = 0;
        float wingRevAngle = 0;

        PropellerBase mainPropeller = new PropellerBase("mainPropeller", cachedEntity, new Vec3(0, 4.7, 0),
                new Angle(0.01, new Angle(0.28), new Angle(0.01)));
        SeatFL seat = new SeatFL("seat01", cachedEntity, true,
                90, ComponentFL.Orientation.North,
                new Vec3(0.8, 1.035, 4.3),
                new Vec3(1,1,1)
        );

        GroundCheckFL groundCheckFL = new GroundCheckFL("test",cachedEntity,new Vec3(0,-20,0),new Vec3(1,1,1));
        EngineFL engine = new ModTestEngine(cachedEntity, "engine", new Vec3(0, 2.7, -1.6));
        public UH_1D_SAR_EntityFLProvider(RideableFL fl) {
            super(fl);
        }

        @Override
        public void INIT() {
            super.INIT();
            fl.setMass(300);
            fl.pivotPos = new Vec3(-0.1, 1, 0.5);
            engine.setRelativeAABB(0.7,1.1,2.6);
            engine.setMass(500);
            mainPropeller.setRelativeAABB(20,0.2,20);
            mainPropeller.setMass(100);
            fl.addComponent(mainPropeller);
            fl.addComponent(seat);
            fl.addComponent(groundCheckFL);
            fl.addComponent(engine);
            //垂直尾翼
            fl.addComponent(new StabilizerBase("vertical_stabilizer", cachedEntity,
                    new Vec3(0, 2.8, -17),
                    0.03, 2, 1));
            //水平尾翼
            fl.addComponent(new StabilizerBase("horizontal_stabilizer", cachedEntity,
                    new Vec3(0, 1.8, -12),
                    4, 0.03, 0.7));

            fl.rideablePhysicsObject.setMass(fl.getMass());
            fl.rideablePhysicsObject.setCurrentPos(cachedEntity.position());
        }

        @Override
        public void tick() {
            super.tick();
            mainPropeller.setRevolutionSpeed(engine.getRevolutionSpeed());

            if (cachedEntity.level().isClientSide) {
                CompoundTag nbt = new CompoundTag();
                Vec3 pos = cachedEntity.position();
                nbt.putDouble("x", pos.x);
                nbt.putDouble("y", pos.y);
                nbt.putDouble("z", pos.z);
                ACHMessages.sendToServer(new CustomSyncableC2SPacket(
                        cachedEntity.getId(), cachedEntity.getUUID(), nbt, ACHeliPacketType.Active));
            }

            cachedEntity.move(MoverType.SELF, cachedEntity.getDeltaMovement());
        }

        @Override
        public void renderTick(PoseStack matrices, float tickDelta) {
            super.renderTick(matrices, tickDelta);
            RideableFL fl = this.fl;
            Quaternionf target = fl.totalRotation;
            target.rotateY((float) fl.totalYMomentum);
            target.rotateX((float) fl.totalXMomentum);
            target.rotateZ((float) fl.totalZMomentum);
            fl.totalRotation.slerp(target, 0.1f * tickDelta);

            double dragRatio = 0.0000002 * speed;
            double rotateRatio = 0.998 * revRatio();;
            double rotateYawRatio = 0.998;

            if (cachedEntity.onGround()) {
                //触地算法
                double groundDragRatio = 0.99;
                cachedEntity.setDeltaMovement(cachedEntity.getDeltaMovement().multiply(groundDragRatio, 1, groundDragRatio));
                target.rotateZ((float) -(Math.toDegrees(EntityDirectionUtils.getRoll(fl.totalRotation))/77));
                target.rotateX((float) -(Math.toDegrees(EntityDirectionUtils.getPitch(fl.totalRotation))/77));
                rotateYawRatio *= 0.3;

            }
            fl.totalYMomentum *= rotateYawRatio;
            fl.totalXMomentum *= rotateRatio;
            fl.totalZMomentum *= rotateRatio;



            double liftForceNum = mainPropeller.getForce().y;//主螺旋桨升力
            // 计算升力的方向向量（使用 Vec3）
            Vec3 liftDirection = EntityDirectionUtils.getUpDirection(RotateWith.translateForRiseRotation(fl.totalRotation));
            liftDirection = new Vec3(liftDirection.x(), liftDirection.y(), liftDirection.z());

            Vec3 outputForce = Vec3.ZERO;
            Vec3 dragForce = Vec3.ZERO;
            Vec3 gravity = new Vec3(0, 115 * 2, 0);

            Vec3 v = cachedEntity.getDeltaMovement();
            speed = v.length() * 100;
            Vec3 horizontalVelocity = v.multiply(1, 0, 1);
            double horizontalSpeed = horizontalVelocity.length() * 100;


            // 计算攻角升力和阻力

            float attackRadians = Aerodynamics.getAngleOfAttack(v, RotateWith.translateForRiseRotation(fl.totalRotation));
            double attackAngle = Math.toDegrees(attackRadians);
            double upDownRatio = Math.cos(attackRadians);
            double noAttackRatio = 1; //诱导升力比
            if (horizontalSpeed > 30) {
                noAttackRatio = 1.212 - Math.abs(upDownRatio);
            }
            if (horizontalSpeed > 50) {
                noAttackRatio = 1.3 - Math.abs(upDownRatio);
            }
            if (horizontalSpeed > 90) {
                noAttackRatio = 1.34 - Math.abs(upDownRatio);
            }
            if (horizontalSpeed > 150) {
                noAttackRatio = 1.37 - Math.abs(upDownRatio);
            }


            Vec3 liftForce = liftDirection.multiply(PhysicsEngine.every(liftForceNum * noAttackRatio));
            Vec3 f1 = liftForce.subtract(gravity);// 计算重力与牵引力合力 F1
            Vec3 nowPos = cachedEntity.position();
            if (lastPos != null) {
                //计算阻力大小
                dragForce = EntityDirectionUtils.getDirectionVector(lastPos, nowPos);
                dragForce = dragForce.multiply(PhysicsEngine.every(dragRatio));
            }
            lastPos = nowPos;


            outputForce = outputForce.add(f1);
            outputForce = outputForce.add(dragForce);

            Vec3 attackAngleLiftForce = Aerodynamics.calculateLift(v, fl.totalRotation).multiply(PhysicsEngine.every(2));
            Vec3 attackAngleDragForce = Vec3.ZERO;
            if (upDownRatio > 0){ //上翼面迎风
                attackAngleDragForce = Aerodynamics.calculateDrag(v, fl.totalRotation).multiply(PhysicsEngine.every(100));
            } else {
                attackAngleDragForce = Aerodynamics.calculateDrag(v, fl.totalRotation).multiply(PhysicsEngine.every(70));
            }

            outputForce = outputForce.add(attackAngleLiftForce);
            outputForce = outputForce.add(attackAngleDragForce);
            if (upDownRatio > 0){ //上翼面迎风
//            System.out.println("up");
//            outputForce = outputForce.add(dragForce.multiply(upDownRatio));
                outputForce = outputForce.subtract(dragForce.multiply(PhysicsEngine.every(speed*13.7*upDownRatio)));
//            outputForce = outputForce.subtract(liftForce.multiply(speed/8480)).multiply(upDownRatio * revRatio());

                //需要判断头顶方向与地平线的夹角
//            outputForce = outputForce.subtract(gravity.multiply(speed/20*upDownRatio));

            } else { //下翼面迎风
//            System.out.println("down");

                //涡环
                double vortexRatio = 1;

//            if (horizontalSpeed < 50) {
//                vortexRatio = 1/(50 - horizontalSpeed);
//            }
//            if (vortexRatio < (double) 1 /6){
//                vortexRatio = (double) 1 /6;
//            }

                outputForce = outputForce.subtract(liftForce.multiply(PhysicsEngine.every(0.005+(speed/30))).multiply(PhysicsEngine.every(vortexRatio * upDownRatio * revRatio())));
                outputForce = outputForce.subtract(dragForce.multiply(PhysicsEngine.every(7+(speed/70))).multiply(PhysicsEngine.every(vortexRatio * upDownRatio * revRatio())));
            }
//        System.out.println("upDownRatio " + upDownRatio + "       attackAngle " + attackAngle);
            fl.rideablePhysicsObject.setCurrentForce(outputForce);
            fl.rideablePhysicsObject.setCurrentVelocity(cachedEntity.getDeltaMovement());
            fl.rideablePhysicsObject.physicsObjTick((float) 30 /Minecraft.getInstance().getFps());

            Vec3 velocity = fl.rideablePhysicsObject.getCurrentVelocity(cachedEntity.getDeltaMovement());
            if (! fl.rideablePhysicsObject.getDisabled()) {
                cachedEntity.setDeltaMovement(velocity);
            }

//            System.out.println(tickDelta);

        }


        public void bladeChange(float delta) {
            AbstractAngle angle = mainPropeller.getAttackAngle();
            angle.setAngle(new Angle(angle.getAngleNum() + delta));
            mainPropeller.setAttackAngle(angle);
//            getRideableNbt().putDouble("mainPropellerAttackAngle", getRideableNbt().getDouble("mainPropellerAttackAngle") + delta);
//            EventData.setState(this);
//            collectivePitchLever.setPitchLength((float) (1-getTotalRatio() * collectivePitchLever.getPitchMaxLength()));
        }


        public void bladeSet(float num) {
            float real = (float) (mainPropeller.getAttackAngle().getUpperLimit().getAngleNum() * num);
            AbstractAngle angle = mainPropeller.getAttackAngle();
            angle.setAngle(new Angle(real));
            mainPropeller.setAttackAngle(angle);
//            getRideableNbt().putDouble("mainPropellerAttackAngle", real);
//            EventData.setState(this);
//            collectivePitchLever.setPitchLength((float) (1-getTotalRatio() * collectivePitchLever.getPitchMaxLength()));
        }


        @Override
        public void onClientTick() {
            if (KeyBinding.ENGINE_BUTTON_RIGHT.isDown()) {
                engine.engineSwitch();

            }
            if (KeyBinding.CYCLIC_PUSH.isDown()) {
                getFL().totalZMomentum += 0.0002;

            }
            if (KeyBinding.CYCLIC_PULL.isDown()) {
                getFL().totalZMomentum -= 0.0002;

            }
            if (KeyBinding.CYCLIC_LEFT.isDown()) {
                getFL().totalXMomentum += 0.0002;

            }
            if (KeyBinding.CYCLIC_RIGHT.isDown()) {
                getFL().totalXMomentum -= 0.0002;

            }

            if (KeyBinding.RUDDER_LEFT.isDown()) {
                getFL().totalYMomentum += 0.0002;

            }
            if (KeyBinding.RUDDER_RIGHT.isDown()) {
                getFL().totalYMomentum -= 0.0002;

            }
            if (KeyBinding.COLLECTIVE_UP.isDown()) {
                bladeChange(0.001f);

            }
            if (KeyBinding.COLLECTIVE_DOWN.isDown()) {
                bladeChange(-0.001f);

            }
        }

        public Vec3 getTestPos() {
            Vec3 pos = new Vec3(Debugging.testing[0], Debugging.testing[1], Debugging.testing[2]);
            if (cachedEntity.level().isClientSide) {
                Minecraft.getInstance().player.sendSystemMessage(Component.literal("testPos: "+pos));
            }
            return pos;
        }

        public double revRatio () { //旋翼转速比
            double maxRev = engine.getMaximumRevSpeed();
            double propellerRev = mainPropeller.getRevolutionSpeed();
            return propellerRev/ maxRev;
        }


        @Override
        public void interact(Player player, InteractionHand hand) {

        }

        @Override
        public CompoundTag serverReceiveAndSending(CompoundTag serverOriginNbt, ServerPlayer executingPlayer, ACHeliPacketType packetType) {
            if (packetType == ACHeliPacketType.Active) {
                cachedEntity.setPos(
                        serverOriginNbt.getDouble("x"),
                        serverOriginNbt.getDouble("y"),
                        serverOriginNbt.getDouble("z")
                );
            }
            return super.serverReceiveAndSending(serverOriginNbt, executingPlayer, packetType);
        }

        @Override
        public void clientReceive(CompoundTag receivedNbt, boolean fromSelf, ACHeliPacketType packetType) {
            super.clientReceive(receivedNbt, fromSelf, packetType);
        }

        @Override
        public void render(EntityRendererProvider.Context context, RideableEntity entity, float yaw, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight) {
            wingRevAngle += (float) (revRatio() * 30);
            wingRevAngle = wingRevAngle % 360;
            ItemRenderer itemRenderer = context.getItemRenderer();
//            Vec3 testPos = getTestPos();
            poseStack.scale(1.8f,1.8f,1.8f);
//            // 坐标系调整
            poseStack.mulPose(Axis.YP.rotationDegrees(90));
            fl.applyRotation(poseStack);
//            poseStack.mulPose(Axis.XP.rotationDegrees(180));
//            poseStack.mulPose(Axis.YP.rotationDegrees(90));
//            poseStack.scale(0.8F, 0.8F, 0.8F);
            super.render(context, entity, yaw, partialTick, poseStack, buffer, packedLight);
            poseStack.translate(fl.pivotX(), fl.pivotY(), fl.pivotZ());
            itemRenderer.renderStatic(bodyItemStack, ItemDisplayContext.GROUND, packedLight, OverlayTexture.NO_OVERLAY, poseStack, buffer, entity.level(), 0);


            poseStack.translate(-0.16, 1.73, -0.5);
            poseStack.mulPose(Axis.YP.rotationDegrees(wingRevAngle));
            poseStack.translate(0.5, 0, 0.5);
            itemRenderer.renderStatic(mainPropellerItemStack, ItemDisplayContext.GROUND, packedLight, OverlayTexture.NO_OVERLAY, poseStack, buffer, entity.level(), 0);
            poseStack.translate(-0.5, 0, -0.5);
            poseStack.mulPose(Axis.YP.rotationDegrees(-wingRevAngle));
            poseStack.translate(0.16, -1.73, 0.5);



//            poseStack.translate(testPos.x,testPos.y,testPos.z);
            poseStack.translate(8.865, 2.554, -0.01);
            poseStack.mulPose(Axis.ZP.rotationDegrees(wingRevAngle));
            poseStack.translate(0.5, 0.5, 0);
            itemRenderer.renderStatic(tinyPropellerItemStack, ItemDisplayContext.GROUND, packedLight, OverlayTexture.NO_OVERLAY, poseStack, buffer, entity.level(), 0);
            poseStack.translate(-0.5, -0.5, 0);
            poseStack.mulPose(Axis.ZP.rotationDegrees(-wingRevAngle));
            poseStack.translate(-8.865, -2.554, 0.01);
//            poseStack.translate(-testPos.x,-testPos.y,-testPos.z);


            poseStack.translate(-fl.pivotX(), -fl.pivotY(), -fl.pivotZ());

        }
    }


}
